import { Client } from 'elasticsearch';
import { v4 as uuidv4 } from 'uuid';
import config from '../config';
import Article from '../models/Article';
import Tag from '../models/Tag';
import { Op } from 'sequelize';

// Elasticsearch客户端
const esClient = new Client({
  host: `${config.elasticsearch.host}:${config.elasticsearch.port}`
});

// 搜索参数接口
interface SearchParams {
  query: string;
  page: number;
  pageSize: number;
  sortBy: string;
  categoryId?: string;
  tagIds: number[];
}

/**
 * 搜索服务
 * @description 处理全文搜索相关功能
 */
class SearchService {
  /**
   * 索引文章
   * @param article 文章对象
   */
  public async indexArticle(article: any): Promise<void> {
    try {
      await esClient.index({
        index: 'articles',
        id: article.id,
        body: {
          id: article.id,
          title: article.title,
          content: article.content,
          summary: article.summary,
          tags: article.tags?.map((tag: any) => tag.name) || [],
          category: article.category?.name || '',
          author: article.author?.nickname || '',
          slug: article.slug,
          status: article.status,
          created_at: article.created_at,
          updated_at: article.updated_at,
          published_at: article.published_at,
        }
      });
    } catch (error) {
      console.error('索引文章失败:', error);
      throw error;
    }
  }
  
  /**
   * 删除文章索引
   * @param articleId 文章ID
   */
  public async removeArticleIndex(articleId: string): Promise<void> {
    try {
      await esClient.delete({
        index: 'articles',
        id: articleId
      });
    } catch (error) {
      console.error('删除文章索引失败:', error);
      throw error;
    }
  }
  
  /**
   * 全文搜索
   * @param params 搜索参数
   */
  public async search(params: SearchParams): Promise<any> {
    try {
      const { query, page, pageSize, sortBy, categoryId, tagIds } = params;
      const from = (page - 1) * pageSize;
      
      // 构建查询
      const mustClauses: any[] = [
        { 
          multi_match: {
            query,
            fields: ['title^3', 'content', 'summary^2', 'tags^2', 'category'],
            type: 'best_fields',
            fuzziness: 'AUTO'
          }
        },
        { match: { status: 'published' } }
      ];
      
      // 分类过滤
      if (categoryId) {
        mustClauses.push({ term: { 'category_id': categoryId } });
      }
      
      // 标签过滤
      if (tagIds.length > 0) {
        mustClauses.push({
          terms: { 'tags.id': tagIds }
        });
      }
      
      // 排序
      let sort = [];
      switch (sortBy) {
        case 'newest':
          sort = [{ published_at: { order: 'desc' } }];
          break;
        case 'popular':
          sort = [{ view_count: { order: 'desc' } }];
          break;
        default:
          sort = [{ _score: { order: 'desc' } }];
      }
      
      // 执行搜索
      const searchResult = await esClient.search({
        index: 'articles',
        body: {
          query: {
            bool: {
              must: mustClauses
            }
          },
          highlight: {
            fields: {
              title: {},
              content: {},
              summary: {}
            },
            pre_tags: ['<em>'],
            post_tags: ['</em>'],
            fragment_size: 150,
            number_of_fragments: 3
          },
          from,
          size: pageSize,
          sort
        }
      });
      
      // 处理结果
      const hits = searchResult.hits.hits;
      const total = searchResult.hits.total;
      
      // 映射搜索结果
      const items = await Promise.all(hits.map(async (hit: any) => {
        const source = hit._source;
        
        // 获取文章详细信息
        const article = await Article.findByPk(source.id, {
          include: [
            { model: Tag, as: 'tags' }
          ]
        });
        
        if (!article) return null;
        
        // 提取高亮结果
        let highlightedContent = '';
        if (hit.highlight) {
          if (hit.highlight.title) {
            highlightedContent += hit.highlight.title.join(' ... ');
          }
          
          if (hit.highlight.content) {
            highlightedContent += highlightedContent ? ' ... ' : '';
            highlightedContent += hit.highlight.content.join(' ... ');
          }
          
          if (hit.highlight.summary) {
            highlightedContent += highlightedContent ? ' ... ' : '';
            highlightedContent += hit.highlight.summary.join(' ... ');
          }
        }
        
        return {
          id: article.id,
          title: article.title,
          slug: article.slug,
          summary: article.summary,
          publishedAt: article.published_at,
          viewCount: article.view_count,
          commentCount: article.comment_count,
          tags: article.tags,
          highlightedContent: highlightedContent || null
        };
      }));
      
      // 过滤掉null值
      const filteredItems = items.filter(item => item !== null);
      
      return {
        items: filteredItems,
        total: typeof total === 'object' ? total.value : total,
        page,
        pageSize,
        totalPages: Math.ceil((typeof total === 'object' ? total.value : total) / pageSize)
      };
    } catch (error) {
      console.error('搜索失败:', error);
      throw error;
    }
  }
  
  /**
   * 获取搜索建议
   * @param query 搜索关键词
   */
  public async getSuggestions(query: string): Promise<string[]> {
    try {
      // 从ES获取搜索建议
      const suggestResult = await esClient.search({
        index: 'articles',
        body: {
          suggest: {
            title_suggestion: {
              text: query,
              term: {
                field: 'title',
                suggest_mode: 'popular',
                size: 5
              }
            },
            content_suggestion: {
              text: query,
              term: {
                field: 'content',
                suggest_mode: 'popular',
                size: 5
              }
            }
          },
          size: 0
        }
      });
      
      // 处理结果
      const suggestions: Set<string> = new Set();
      
      // 处理标题建议
      if (suggestResult.suggest && suggestResult.suggest.title_suggestion) {
        suggestResult.suggest.title_suggestion.forEach((suggestion: any) => {
          suggestion.options.forEach((option: any) => {
            suggestions.add(option.text);
          });
        });
      }
      
      // 处理内容建议
      if (suggestResult.suggest && suggestResult.suggest.content_suggestion) {
        suggestResult.suggest.content_suggestion.forEach((suggestion: any) => {
          suggestion.options.forEach((option: any) => {
            suggestions.add(option.text);
          });
        });
      }
      
      // 如果没有找到建议，则尝试从数据库中获取相关标签
      if (suggestions.size === 0) {
        const tags = await Tag.findAll({
          where: {
            name: {
              [Op.like]: `%${query}%`
            }
          },
          limit: 5
        });
        
        tags.forEach(tag => {
          suggestions.add(tag.name);
        });
      }
      
      return Array.from(suggestions);
    } catch (error) {
      console.error('获取搜索建议失败:', error);
      return [];
    }
  }
}

export default new SearchService(); 